home *** CD-ROM | disk | FTP | other *** search
/ Best of Shareware / Best of PC Windows Shareware 1.0 - Wayzata Technology (7111) (1993).iso / mac / ZIPPED / DOS / GRAPHICS / POVSRC.ZIP / MACHINE.ZIP / MAC.SIT / printf2window.c < prev    next >
Text File  |  1992-04-27  |  49KB  |  1,528 lines

  1. /*
  2. ==============================================================================
  3. Project:    POV-Ray
  4.  
  5. File Name:    printf2window.c
  6.  
  7. Description:
  8.     General-purpose printf-capturing routines that allow a console-like
  9.     output window for c programs that otherwise prefer to use printf/fprintf.
  10.     This code was "inspired heavily" from sources such as MacDTS'es TESample,
  11.     MacApp's Transcript window, and previous code of mine.  It is fairly well
  12.     self-contained, and works in MPW C 3.2 and Think C 5.0.
  13.  
  14.     This is the main source file, containing the private definitions and
  15.     code to implement all the needed external and internal support functions.
  16.  
  17. Related Files:
  18.     stdio_p2w.h        - generic header for sources that would otherwise use <stdio.h>
  19.     printf2window.h    - Mac-specific header for p2w routines
  20.     printf2window.c    - the main source for the p2w routines
  21. ------------------------------------------------------------------------------
  22. Author:
  23.     Eduard [esp] Schwan
  24. ------------------------------------------------------------------------------
  25. Copyright 1992 POV-Team.
  26.     This source code is distributed exclusively with POV, and is subject to
  27.     the same distribution restrictions as the rest of the source code.
  28.  
  29. *  Copying, distribution and legal info is in the file povlegal.doc which
  30. *  should be distributed with this file. If povlegal.doc is not available
  31. *  or for more information please contact:
  32. *
  33. *       Drew Wells [POV-Team Leader] 
  34. *       CIS: 73767,1244  Internet: 73767.1244@compuserve.com
  35. *       Phone: (213) 254-4041
  36.  
  37. ------------------------------------------------------------------------------
  38. Change History:
  39.     920318    [esp]    Created.
  40.     920325    [esp]    Added init/Terminate, major redesign of std c fns.
  41.     920327    [esp]    Robustized AddCString code that handles TERec-is-full delete logic
  42.     920329    [esp]    Added AdjustScrollBars call in AddCString to update scrollers as text is added
  43.     920330    [esp]    Updated file header with copyright & related files info
  44.     920401    [esp]    Added p2wSignature to window record for safety checking
  45.     920402    [esp]    Fixed cr/lf bug in bottleneck routine
  46.     920412    [esp]    Fixed potential integer overflow in comparison in AddCString routine
  47.     920412    [esp]    Added most function header comments, added windBounds support in Newp2wWindow, fixed scroller activate bug
  48.     920413    [esp]    Fixed misbehavin' scrollbars hilite upon activate/deactivate
  49. ==============================================================================
  50. */
  51.  
  52. /* Standard C library headers */
  53. #include <stdarg.h>        // ANSI C variable length argument support
  54. #include <string.h>        // strlen
  55.  
  56. /* Macintosh-specific headers */
  57. #include <Types.h>
  58. #include <Controls.h>
  59. #include <Dialogs.h>
  60. #include <Files.h>
  61. #include <Memory.h>
  62. #include <OSUtils.h>
  63. #include <Resources.h>
  64. #include <Windows.h>
  65. #ifdef _applec
  66. #include <strings.h>        /*p2cstr*/
  67. #endif
  68.  
  69. #include "printf2window.h"    /* our defs AND stdio.h for sprintf, etc. */
  70.  
  71.  
  72. // ==== Constant definitions
  73.  
  74. // Comment USE_P2W_RESOURCES out to create the window & controls from scratch..
  75. // Leave it in to create them from resources
  76.  
  77. #define    USE_P2W_RESOURCES    true
  78.  
  79.  
  80. // Resource IDs of supporting p2w resources
  81.  
  82. #ifdef USE_P2W_RESOURCES
  83. #define    kp2w_WindowID        9601
  84. #define    kp2w_VScrollID        9601
  85. #define    kp2w_HScrollID        9602
  86. #endif USE_P2W_RESOURCES
  87.  
  88.  
  89. // Magic p2w window record signature value
  90.  
  91. #define    kp2wWindowSignature    'p2w '
  92.  
  93.  
  94. // kTextMargin is the number of pixels we leave blank at the edge of the window.
  95.  
  96. #define kTextMargin                2
  97.  
  98.  
  99. // kControlInvisible is used to 'turn off' controls (i.e., cause the control not
  100. // to be redrawn as a result of some Control Manager call such as SetCtlValue)
  101. // by being put into the contrlVis field of the record. kControlVisible is used
  102. // the same way to 'turn on' the control.
  103.  
  104. #define kControlInvisible        0
  105. #define kControlVisible            0xFF
  106.  
  107.  
  108. // kControlHiliteActive is used to activate controls (contrlHilite)
  109. // kControlHiliteInactive is used to deactivate controls (contrlHilite)
  110.  
  111. #define kControlHiliteActive        0
  112. #define kControlHiliteInactive        0xFF
  113.  
  114.  
  115. // kButtonScroll is how many pixels to scroll horizontally when the button part
  116. // of the horizontal scrollbar is pressed.
  117.  
  118. #define kButtonScroll            4
  119.  
  120. // kScrollbarAdjust and kScrollbarWidth are used in calculating
  121. // values for control positioning and sizing.
  122.  
  123. #define kScrollbarWidth            16
  124. #define kScrollbarAdjust        (kScrollbarWidth - 1)
  125.  
  126.  
  127. // kScrollTweek compensates for off-by-one requirements of the scrollbars
  128. // to have borders coincide with the growbox.
  129.  
  130. #define kScrollTweek            2
  131.  
  132.  
  133. // kMaxTELength is an arbitrary number used to limit the length of text in the TERec
  134. // so that various errors won't occur from too many characters in the text.  When the
  135. // string to be added exceeds kMaxTELength, then strlen+kTEDeleteChunkSize
  136. // characters will be deleted from the beginning of the TERec.  This lets the TE
  137. // buffer stay pretty full while characters "fall off the top" of the buffer, and
  138. // insures that the performance delay of deleting from the front of the buffer
  139. // only happens every once in awhile, instead of for every single additional
  140. // string added.  kTEDeleteChunkSize should probably be between 1k and 20k..
  141.  
  142. #define    kMaxTELength            32700    // 32700 is pretty close to 32767, no?
  143. #define    kTEDeleteChunkSize        5000    // should be between 1000 and 20000
  144.  
  145.  
  146. // kMinDocSize is the smallest horiz/vert size of a grown window.
  147.  
  148. #define    kMinDocSize                100
  149.  
  150.  
  151. // kMaxStdIOBuffSize is the largest supported size of a single formatted
  152. // stdio C string.  Note that internally, a relocatable buffer of this size
  153. // will be allocated.
  154.  
  155. #define    kMaxStdIOBuffSize        1024
  156.  
  157.  
  158. // internal macro definitions
  159.  
  160. // Define some structure accessing macros for efficiency.
  161. #define GET_HIWORD(aLong)    (((aLong)>>16)&0x0FFFFL)
  162. #define GET_LOWORD(aLong)    ((aLong)&0x0FFFFL)
  163. #define GET_TOPLEFT_POINT(aRect)    (*(Point*)&(aRect).top)
  164. #define GET_BOTRIGHT_POINT(aRect)    (*(Point*)&(aRect).bottom)
  165. #define GET_RECT_WIDTH(aRect)        ((aRect).right - (aRect).left)
  166. #define GET_RECT_HEIGHT(aRect)        ((aRect).bottom - (aRect).top)
  167.  
  168. /*
  169. ----------------------------------
  170. prototypes for internal routines
  171. ----------------------------------
  172. */
  173.  
  174. static void p2wi_GetTERect(const p2w_WindowPtr thep2wWindow, Rect *teRect);
  175. static void p2wi_AdjustTE(const p2w_WindowPtr thep2wWindow);
  176. static void p2wi_AdjustViewRect(TEHandle p2wTE);
  177. static void p2wi_CommonAdjustScroller(const Boolean isVert, const p2w_WindowPtr thep2wWindow, ControlHandle control, TEHandle theTEHandle, const Boolean canRedraw);
  178. static void p2wi_AdjustScrollValues(const p2w_WindowPtr thep2wWindow, const Boolean doRedraw);
  179. static void p2wi_AdjustScrollSizes(const p2w_WindowPtr thep2wWindow);
  180. static void p2wi_AdjustScrollbars(const p2w_WindowPtr thep2wWindow, const Boolean doResize);
  181. static void p2wi_ResizeWindow(const p2w_WindowPtr thep2wWindow);
  182. static void p2wi_GetLocalUpdateRegion(const p2w_WindowPtr thep2wWindow, RgnHandle localRgn);
  183. static void p2wi_CommonScrollAction(ControlHandle control, short *amount);
  184. pascal void p2wi_VScrollActionProc(ControlHandle control, short part);
  185. pascal void p2wi_HScrollActionProc(ControlHandle control, short part);
  186. static int p2w_StdCOut_BottleNeck(const FILE *stream);
  187. static int p2w_vfprintf(FILE *stream, const char *format, va_list va_args);
  188.  
  189.  
  190.  
  191. /*
  192. ----------------------------------
  193. global variable definitions
  194. ----------------------------------
  195. */
  196.  
  197. static Handle            p2w_Stdio_OutBuf_Hdl = NULL;
  198. static p2w_WindowPtr    local_p2wWindow = NULL;
  199.  
  200.  
  201.  
  202. /*---------------------------------------------------------------------*/
  203. /*==== Main interface routines ====*/
  204.  
  205.  
  206. /*
  207. ******************************************************************************
  208. Name:
  209.     p2w_Init
  210. ------------------------------------------------------------------------------
  211. Purpose:
  212.     Primary (one-time) initialization of the p2w routines
  213. ------------------------------------------------------------------------------
  214. Description:
  215.     pre-allocates internal storage & initializes variables
  216. ------------------------------------------------------------------------------
  217. Parameters:
  218.     void
  219. ------------------------------------------------------------------------------
  220. When Used:
  221.     Called once, when the application starts up
  222. ******************************************************************************
  223. */
  224. OSErr p2w_Init(void)
  225. {
  226.     OSErr    anError = noErr;
  227.  
  228.     // allocate an output character stream buffer to use
  229.     p2w_Stdio_OutBuf_Hdl = NewHandle(kMaxStdIOBuffSize);
  230.     anError = MemError();
  231.     local_p2wWindow = NULL;
  232.  
  233.     return anError;
  234. } // p2w_Init
  235.  
  236.  
  237.  
  238. /*
  239. ******************************************************************************
  240. Name:
  241.     p2w_Terminate
  242. ------------------------------------------------------------------------------
  243. Purpose:
  244.     Primary (one-time) destruction of the p2w routines
  245. ------------------------------------------------------------------------------
  246. Description:
  247.     de-allocates internal storage & invalidates variables
  248. ------------------------------------------------------------------------------
  249. Parameters:
  250.     void
  251. ------------------------------------------------------------------------------
  252. When Used:
  253.     Called once, when the application is shutting down
  254. ******************************************************************************
  255. */
  256. OSErr p2w_Terminate(void)
  257. {
  258.     OSErr    anError = noErr;
  259.  
  260.     if (p2w_Stdio_OutBuf_Hdl)
  261.     {
  262.         DisposeHandle(p2w_Stdio_OutBuf_Hdl);
  263.         anError = MemError();
  264.     }
  265.     p2w_Stdio_OutBuf_Hdl = NULL;
  266.     local_p2wWindow = NULL;
  267.  
  268.     return anError;
  269. } // p2w_Terminate
  270.  
  271.  
  272.  
  273. /*
  274. ******************************************************************************
  275. Name:
  276.     p2w_NewWindow
  277. ------------------------------------------------------------------------------
  278. Purpose:
  279.     Creates a new p2w window structure for use by other p2w routines.
  280. ------------------------------------------------------------------------------
  281. Description:
  282.     Creates a p2w window (either from resources or from parameters),
  283.     initializes it, and shows it if asked.
  284. ------------------------------------------------------------------------------
  285. Parameters:
  286.     windBoundsPtr    Where to place the new window on the screen.
  287.                     If NULL, the resource bounds will be used.
  288.     windTitle        The Pascal title string to use for the new window.
  289.                     If NULL, resource title will be used.
  290.     windIsVisible    TRUE will show window after creation, FALSE will leave hidden.
  291.     windFont        Text Font to use for new window.
  292.     windFontSize    Text Font Size tose for new window.
  293.     anError            Returns any error code, or zero (noErr) if all went OK.
  294. ------------------------------------------------------------------------------
  295. When Used:
  296.     Called when a new p2w window needs to be allocated.  It may or may not
  297.     be shown at this time.  This call mainly creates the window structures.
  298. ******************************************************************************
  299. */
  300. p2w_WindowPtr p2w_NewWindow(const    Rect        *windBoundsPtr,
  301.                             const    Str255        windTitle,
  302.                             const    Boolean        windIsVisible,
  303.                             const    int            windFont,
  304.                             const    short        windFontSize,
  305.                                     OSErr        *anError)
  306. {
  307.     WindowPtr        aWindow;
  308.     Rect            destRect, viewRect, screenRect;
  309.     p2w_WindowPtr    p2wWPtr = NULL;
  310.     GrafPtr            savedPort;
  311.  
  312.     GetPort(&savedPort);    // I'll be back..
  313.  
  314.     /* how big is the screen */
  315.     screenRect = qd.screenBits.bounds;
  316.  
  317.     /* allocate space for our extended p2window record */
  318.     p2wWPtr = (p2w_WindowPtr)NewPtr(sizeof(p2w_WindowRecord));
  319.     *anError = MemError();
  320.     if (!*anError)
  321.     {
  322.         // initialize the p2w record
  323.  
  324.         p2wWPtr->p2wSignature        = kp2wWindowSignature; // bless this special window record
  325.         p2wWPtr->p2wOpenedOK        = false; // until actually opened later
  326.         p2wWPtr->p2wTEHandle        = NULL;
  327.         p2wWPtr->p2wVScroller        = NULL;
  328.         p2wWPtr->p2wHScroller        = NULL;
  329.         p2wWPtr->p2wClickHandler    = NULL;
  330.         p2wWPtr->p2wMaxDocWidth        = GET_RECT_WIDTH(screenRect) - kScrollbarWidth - 2*kTextMargin - 10;
  331.         p2wWPtr->p2wAlwaysScrollToBottom    = true;
  332.  
  333.         /* now create the Window */
  334. #ifdef USE_P2W_RESOURCES
  335.         aWindow = GetNewWindow(kp2w_WindowID, p2wWPtr, (WindowPtr)-1);
  336.         *anError = ResError();
  337. #else
  338.         aWindow = NewWindow(p2wWPtr, windBounds, windTitle, isVisible, documentProc, (WindowPtr)-1, hasGoAway, 0);
  339.         *anError = MemError();
  340. #endif USE_P2W_RESOURCES
  341.     }
  342.  
  343.     /* Move the window to user-specified position? */
  344.     if ((!*anError) && (windBoundsPtr != NULL))
  345.     {
  346.         MoveWindow(aWindow, (*windBoundsPtr).left, (*windBoundsPtr).top, false);
  347.         SizeWindow(aWindow, GET_RECT_WIDTH(*windBoundsPtr), GET_RECT_HEIGHT(*windBoundsPtr), false);
  348.     }
  349.  
  350.     if (!*anError)
  351.     {
  352.         p2wWPtr->p2wOpenedOK = true; // now its OK to call CloseWindow later..
  353.  
  354.         /* Set its title to what the user passed in, if non-null */
  355.         if (windTitle)                            // not a NULL pointer?
  356.             if (*windTitle)                        // not an empty string?
  357.                 SetWTitle(aWindow, windTitle);    // then do it!
  358.  
  359.         /* set up the font in the port */
  360.         SetPort(aWindow);
  361.         TextFont(windFont);
  362.         TextSize(windFontSize);
  363.  
  364.         /* set up the EditText buffer & area */
  365.         p2wi_GetTERect(p2wWPtr, &viewRect);
  366.         destRect = viewRect;
  367.         destRect.right = destRect.left + p2wWPtr->p2wMaxDocWidth;
  368.         p2wWPtr->p2wTEHandle = TENew(&destRect, &viewRect);
  369.         *anError = MemError();
  370.     }
  371.  
  372.     if (!*anError)
  373.     {
  374.         p2wi_AdjustViewRect(p2wWPtr->p2wTEHandle);
  375.         // turn on auto-scrolling
  376. //        TEAutoView(true, p2wWPtr->p2wTEHandle); -- later, when we auto-connect to scrollbars
  377.     }
  378.  
  379.     /* Create vertical scrollbar */
  380.     if (!*anError)
  381.     {
  382. #ifdef USE_P2W_RESOURCES
  383.         p2wWPtr->p2wVScroller = GetNewControl(kp2w_VScrollID, aWindow);
  384.         *anError = ResError();
  385. #else
  386.         p2wWPtr->p2wVScroller = NewControl(aWindow, aWindow^.portRect, "", false, 0, 0, 1, scrollBarProc, 0);
  387.         *anError = MemError();
  388. #endif USE_P2W_RESOURCES
  389.     }
  390.  
  391.     /* Create horizontal scrollbar */
  392.     if (!*anError)
  393.     {
  394. #ifdef USE_P2W_RESOURCES
  395.         p2wWPtr->p2wHScroller = GetNewControl(kp2w_HScrollID, aWindow);
  396.         *anError = ResError();
  397. #else
  398.         p2wWPtr->p2wHScroller = NewControl(aWindow, aWindow^.portRect, "", false, 0, 0, 1, scrollBarProc, 0);
  399.         *anError = MemError();
  400. #endif USE_P2W_RESOURCES
  401.     }
  402.  
  403.     // adjust & draw the controls, draw the window
  404.     if (!*anError)
  405.     {
  406.         p2wi_AdjustScrollbars(p2wWPtr, true/*kResize*/);
  407.         if (windIsVisible)
  408.             ShowWindow(aWindow);
  409.     }
  410.  
  411.     // Return to port after storm
  412.     SetPort(savedPort);    // I'm back..
  413.  
  414.     // close & dispose if any errors happened!
  415.     if (*anError)
  416.     {
  417.         p2w_DisposeWindow(p2wWPtr);
  418.         // if errors happened, don't give user any pointers
  419.         p2wWPtr = NULL;
  420.     }
  421.  
  422.     // remember this for the StdIO routines later..
  423.     local_p2wWindow = p2wWPtr;
  424.  
  425.     return (p2wWPtr);
  426.  
  427. } // p2w_NewWindow
  428.  
  429.  
  430.  
  431. /*
  432. ******************************************************************************
  433. Name:
  434.     p2w_DisposeWindow
  435. ------------------------------------------------------------------------------
  436. Purpose:
  437.     Deletes an existing p2w window structure and its related TE danglies.
  438. ------------------------------------------------------------------------------
  439. Description:
  440.     Disposes of the TE record, closes the window/grafport, and disposes
  441.     of the window/grafport itself.
  442. ------------------------------------------------------------------------------
  443. Parameters:
  444.     the_p2wPtr        The p2w window to dispose.
  445. ------------------------------------------------------------------------------
  446. When Used:
  447.     Called when a p2w window is no longer needed.
  448. ******************************************************************************
  449. */
  450. void p2w_DisposeWindow(p2w_WindowPtr the_p2wPtr)
  451. {
  452.     // Is the window pointer not null?
  453.     if (the_p2wPtr)
  454.         // is this really one of our p2w windows?
  455.         // (We don't want to dispose extra stuff if it's really
  456.         // a normal [sheep] WindowPtr passed in as a [wolf] p2w_WindowPtr!)
  457.         if (the_p2wPtr->p2wSignature == kp2wWindowSignature)
  458.         {
  459.             // Dispose Window/GrafPort danglies if opened ok
  460.             if (the_p2wPtr->p2wOpenedOK)
  461.                 CloseWindow((WindowPtr)the_p2wPtr);
  462.             // Dispose of our TE Record
  463.             if (the_p2wPtr->p2wTEHandle)
  464.                 TEDispose(the_p2wPtr->p2wTEHandle);
  465.             // set fields back to nil, to help catch anyone touching them after dispose!
  466.             the_p2wPtr->p2wOpenedOK        = false;
  467.             the_p2wPtr->p2wTEHandle        = NULL;
  468.             the_p2wPtr->p2wVScroller    = NULL;
  469.             the_p2wPtr->p2wHScroller    = NULL;
  470.             the_p2wPtr->p2wClickHandler    = NULL;
  471.             // Dispose our version of window record itself now
  472.             DisposePtr((Ptr)the_p2wPtr);
  473.             local_p2wWindow = NULL;
  474.         }
  475. } // p2w_DisposeWindow
  476.  
  477.  
  478. /*
  479. ******************************************************************************
  480. Name:
  481.     p2w_AddCString
  482. ------------------------------------------------------------------------------
  483. Purpose:
  484.     Adds the text in the C-style string passed to the p2w window.
  485. ------------------------------------------------------------------------------
  486. Description:
  487. ------------------------------------------------------------------------------
  488. Parameters:
  489.     the_p2wPtr        The p2w window to add to.
  490.     theCStrPtr        The string of text to add.
  491.     p2w_AddCString    function returns zero if ok, or an error #.
  492. ------------------------------------------------------------------------------
  493. When Used:
  494.     Called when text is to be added to the p2w window.
  495. ******************************************************************************
  496. */
  497. OSErr p2w_AddCString(p2w_WindowPtr the_p2wPtr, const char * theCStrPtr)
  498. {
  499.     OSErr    anError = noErr;
  500.     long    theStrLen;
  501.  
  502.     if (the_p2wPtr && theCStrPtr)        // if window and string ptrs are valid
  503.         // is this really one of our p2w windows?
  504.         // (We don't want to fiddle with extra stuff if it's really
  505.         // a normal [sheep] WindowPtr passed in as a [wolf] p2w_WindowPtr!)
  506.         if (the_p2wPtr->p2wSignature == kp2wWindowSignature)
  507.             if (the_p2wPtr->p2wTEHandle)
  508.             {    // TE Record is valid
  509.                 theStrLen = strlen(theCStrPtr);
  510.                 if (theStrLen > 0)    // if string is not empty, add it
  511.                 {
  512.                     // If TE is too full, need to delete some at beginning before adding
  513.                     // (this looks weird, but it is the Mathematically Correct way to
  514.                     // compare numbers close to the edge of 32767-land.. note that
  515.                     // teLength+theStrLen could overflow, so we subtract instead.)
  516.                     if ((**(the_p2wPtr->p2wTEHandle)).teLength > (kMaxTELength - theStrLen))
  517.                     {
  518.                         // Delete some text at beginning of TE
  519.                         TESetSelect(0, theStrLen+kTEDeleteChunkSize, the_p2wPtr->p2wTEHandle);
  520.                         TEDelete(the_p2wPtr->p2wTEHandle);
  521.                     }
  522.                     // go to very end of TE (-1 is really +65535 in TE Worlds!)
  523.                     TESetSelect(-1, -1, the_p2wPtr->p2wTEHandle);
  524.                     // stick it in there
  525.                     TEInsert(theCStrPtr, theStrLen, the_p2wPtr->p2wTEHandle);
  526.                     // re-draw the scrollbars, since they may have changed
  527.                     p2wi_AdjustScrollbars(the_p2wPtr, true/*kRedraw*/);
  528.                 }    // theStrLen > 0
  529.             }    // TE Record is valid
  530.     return(anError);
  531. } // p2w_AddCString
  532.  
  533.  
  534. /*
  535. ******************************************************************************
  536. Name:
  537.     p2w_DrawWindow
  538. ------------------------------------------------------------------------------
  539. Purpose:
  540.     Draw the contents of an application window.
  541. ------------------------------------------------------------------------------
  542. Description:
  543.     
  544. ------------------------------------------------------------------------------
  545. Parameters:
  546.     
  547. ------------------------------------------------------------------------------
  548. When Used:
  549.     
  550. ******************************************************************************
  551. */
  552. void p2w_DrawWindow(const p2w_WindowPtr the_p2wPtr)
  553. {
  554.     // move in for the kill
  555.     SetPort((WindowPtr)the_p2wPtr);
  556.     // kill off old bits
  557.     EraseRect(&((WindowPtr)the_p2wPtr)->portRect);
  558.     // regain controls
  559.     DrawGrowIcon((WindowPtr)the_p2wPtr);
  560.     DrawControls((WindowPtr)the_p2wPtr);
  561.     // show them our text
  562.     TEUpdate(&((WindowPtr)the_p2wPtr)->portRect, the_p2wPtr->p2wTEHandle);
  563. } // p2w_DrawWindow
  564.  
  565.  
  566.  
  567. /*
  568. ******************************************************************************
  569. Name:
  570.     p2w_DoUpdate
  571. ------------------------------------------------------------------------------
  572. Purpose:
  573.     Update (redraw) the contents of an application window.
  574. ------------------------------------------------------------------------------
  575. Description:
  576.     
  577. ------------------------------------------------------------------------------
  578. Parameters:
  579.     
  580. ------------------------------------------------------------------------------
  581. When Used:
  582.     
  583. ******************************************************************************
  584. */
  585. void p2w_DoUpdate(const p2w_WindowPtr thep2wWindow)
  586. {
  587.     // move in for the kill
  588.     SetPort((WindowPtr)thep2wWindow);
  589.     BeginUpdate((WindowPtr)thep2wWindow);                /* this sets up the visRgn */
  590.     if (!EmptyRgn(((WindowPtr)thep2wWindow)->visRgn))    /* draw if updating needs to be done */
  591.         p2w_DrawWindow(thep2wWindow);
  592.     EndUpdate((WindowPtr)thep2wWindow);
  593. } // p2w_DoUpdate
  594.  
  595.  
  596. /*
  597. ******************************************************************************
  598. Name:
  599.     p2w_DoActivate
  600. ------------------------------------------------------------------------------
  601. Purpose:
  602.     This is called when a window is activated or deactivated.
  603.     It calls TextEdit to handle the selection.
  604. ------------------------------------------------------------------------------
  605. Description:
  606.     
  607. ------------------------------------------------------------------------------
  608. Parameters:
  609.     
  610. ------------------------------------------------------------------------------
  611. When Used:
  612.     
  613. ******************************************************************************
  614. */
  615. void p2w_DoActivate(const p2w_WindowPtr thep2wWindow, Boolean becomingActive)
  616. {
  617.     RgnHandle    tempRgn, clipRgn;
  618.  
  619.     /* move in for the kill */
  620.     SetPort((WindowPtr)thep2wWindow);
  621.  
  622.     /* the growbox should be changed immediately */
  623.     DrawGrowIcon((WindowPtr)thep2wWindow);
  624.  
  625.     if (becomingActive)
  626.     {
  627.         /*
  628.         since we don╒t want TEActivate to draw a selection in an area where we╒re
  629.         going to erase and redraw, we╒ll clip out the update region before calling it.
  630.         */
  631.         tempRgn = NewRgn();
  632.         clipRgn = NewRgn();
  633.         if (tempRgn && clipRgn)
  634.         {
  635.             p2wi_GetLocalUpdateRegion(thep2wWindow, tempRgn);    /* get localized update region */
  636.             GetClip(clipRgn);
  637.             DiffRgn(clipRgn, tempRgn, tempRgn);        /* subtract updateRgn from clipRgn */
  638.             SetClip(tempRgn);
  639.             TEActivate(thep2wWindow->p2wTEHandle);
  640.             SetClip(clipRgn);                        /* restore the full-blown clipRgn */
  641.             DisposeRgn(tempRgn);
  642.             DisposeRgn(clipRgn);
  643.         }
  644.  
  645.         /* the controls must be redrawn on activation */
  646.         ShowControl(thep2wWindow->p2wVScroller);
  647.         ShowControl(thep2wWindow->p2wHScroller);
  648.     }
  649.     else
  650.     {    /* De-Activating.. */
  651.         TEDeactivate(thep2wWindow->p2wTEHandle);
  652.  
  653.         /* the controls must be hidden on deactivation */
  654.         HideControl(thep2wWindow->p2wVScroller);
  655.         HideControl(thep2wWindow->p2wHScroller);
  656.     }
  657. } // p2w_DoActivate
  658.  
  659.  
  660. /*
  661. ******************************************************************************
  662. Name:
  663.     p2w_DoGrow
  664. ------------------------------------------------------------------------------
  665. Purpose:
  666.     Called when a mouseDown occurs in the grow box of an active
  667.     window. In order to eliminate any 'flicker', we want to
  668.     invalidate only what is necessary. Since p2w_ResizeWindow
  669.     invalidates the whole portRect, we save the old TE
  670.     viewRect, intersect it with the new TE viewRect, and remove
  671.     the result from the update region. However, we must make
  672.     sure that any old update region that might have been around
  673.     gets put back. 
  674. ------------------------------------------------------------------------------
  675. Description:
  676.     
  677. ------------------------------------------------------------------------------
  678. Parameters:
  679.     
  680. ------------------------------------------------------------------------------
  681. When Used:
  682.     
  683. ******************************************************************************
  684. */
  685. void p2w_DoGrow(const p2w_WindowPtr thep2wWindow, EventRecord *theEvent)
  686. {
  687.     long        growResult;
  688.     Rect        tempRect;
  689.     RgnHandle    tempRgn;
  690.     
  691.     // move in for the kill
  692.     SetPort((WindowPtr)thep2wWindow);
  693.  
  694.     /* set up limiting values */
  695.     tempRect = qd.screenBits.bounds;
  696.     tempRect.left = kMinDocSize;
  697.     tempRect.top = kMinDocSize;
  698.  
  699.     growResult = GrowWindow((WindowPtr)thep2wWindow, theEvent->where, &tempRect);
  700.     /* see if it really changed size */
  701.     if (growResult != 0)
  702.     {
  703.         tempRect = (**thep2wWindow->p2wTEHandle).viewRect;    /* save old text box */
  704.         tempRgn = NewRgn();
  705.         p2wi_GetLocalUpdateRegion(thep2wWindow, tempRgn);        /* get localized update region */
  706.         SizeWindow((WindowPtr)thep2wWindow, GET_LOWORD(growResult), GET_HIWORD(growResult), true);
  707.         p2wi_ResizeWindow(thep2wWindow);
  708.  
  709.         /* calculate & validate the region that hasn╒t changed, so it won╒t get redrawn */
  710.         SectRect(&tempRect, &(**thep2wWindow->p2wTEHandle).viewRect, &tempRect);
  711.         ValidRect(&tempRect);                            /* take it out of update */
  712.         InvalRgn(tempRgn);                                /* put back any prior update */
  713.         DisposeRgn(tempRgn);
  714.     }
  715. } // p2w_DoGrow
  716.  
  717.  
  718. /*
  719. ******************************************************************************
  720. Name:
  721.     p2w_DoZoom
  722. ------------------------------------------------------------------------------
  723. Purpose:
  724.     Called when a mouseClick occurs in the zoom box of an active
  725.     window. Everything has to get re-drawn here, so we don't mind
  726.     that p2w_ResizeWindow invalidates the whole portRect. 
  727. ------------------------------------------------------------------------------
  728. Description:
  729.     
  730. ------------------------------------------------------------------------------
  731. Parameters:
  732.     
  733. ------------------------------------------------------------------------------
  734. When Used:
  735.     
  736. ******************************************************************************
  737. */
  738. void p2w_DoZoom(const p2w_WindowPtr thep2wWindow, short part)
  739. {
  740.     EraseRect(&((WindowPtr)thep2wWindow)->portRect);
  741.     ZoomWindow((WindowPtr)thep2wWindow, part, (WindowPtr)thep2wWindow==FrontWindow());
  742.     p2wi_ResizeWindow(thep2wWindow);
  743. } // p2w_DoZoom
  744.  
  745.  
  746. /*
  747. ******************************************************************************
  748. Name:
  749.     p2w_DoContentClick
  750. ------------------------------------------------------------------------------
  751. Purpose:
  752.     This is called when a mouseDown occurs in the content of a window.
  753. ------------------------------------------------------------------------------
  754. Description:
  755.     
  756. ------------------------------------------------------------------------------
  757. Parameters:
  758.     
  759. ------------------------------------------------------------------------------
  760. When Used:
  761.     
  762. ******************************************************************************
  763. */
  764. void p2w_DoContentClick(const p2w_WindowPtr thep2wWindow, EventRecord *theEvent)
  765. {
  766.     Point        mouse;
  767.     ControlHandle control;
  768.     short        part, value;
  769.     Boolean        shiftDown;
  770.     Rect        teRect;
  771.  
  772.     SetPort((WindowPtr)thep2wWindow);
  773.  
  774.     /* get the click position */
  775.     mouse = theEvent->where;
  776.     GlobalToLocal(&mouse);
  777.  
  778.     /* see if we are in the viewRect. if so, we won╒t check the controls */
  779.     p2wi_GetTERect(thep2wWindow, &teRect);
  780.     if (PtInRect(mouse, &teRect))
  781.     {
  782.         /* see if we need to extend the selection */
  783.         shiftDown = (theEvent->modifiers & shiftKey) != 0;    /* extend if Shift is down */
  784.         TEClick(mouse, shiftDown, thep2wWindow->p2wTEHandle);
  785.     }
  786.     else
  787.     {
  788.         part = FindControl(mouse, (WindowPtr)thep2wWindow, &control);
  789.         switch (part)
  790.         {
  791.             case 0:        /* do nothing.. */
  792.                 break;
  793.             case inThumb:
  794.                 value = GetCtlValue(control);
  795.                 part = TrackControl(control, mouse, nil);
  796.                 if (part != 0)
  797.                 {
  798.                     value -= GetCtlValue(control);
  799.                     /* value now has CHANGE in value; if value changed, scroll */
  800.                     if (value != 0)
  801.                         if (control == thep2wWindow->p2wVScroller)
  802.                             TEScroll(0, value * (*thep2wWindow->p2wTEHandle)->lineHeight, thep2wWindow->p2wTEHandle);
  803.                         else
  804.                             TEScroll(value, 0, thep2wWindow->p2wTEHandle);
  805.                 }
  806.                 break;
  807.             default:    /* they clicked in an arrow, so track & scroll */
  808.                 if (control == thep2wWindow->p2wVScroller)
  809.                     value = TrackControl(control, mouse, (ProcPtr) p2wi_VScrollActionProc);
  810.                 else
  811.                 if (control == thep2wWindow->p2wHScroller)
  812.                     value = TrackControl(control, mouse, (ProcPtr) p2wi_HScrollActionProc);
  813.                 break;
  814.         }
  815.     }
  816. } // p2w_DoContentClick
  817.  
  818.  
  819.  
  820. /*---------------------------------------------------------------------*/
  821. /*==== Private internal p2w routines ====*/
  822.     
  823. /*
  824. ******************************************************************************
  825. Name:
  826.     p2wi_GetTERect
  827. ------------------------------------------------------------------------------
  828. Purpose:
  829.     Return a rectangle that is inset from the portRect by the
  830.     size of the scrollbars, plus a bit.
  831. ------------------------------------------------------------------------------
  832. Description:
  833.     
  834. ------------------------------------------------------------------------------
  835. Parameters:
  836.     
  837. ------------------------------------------------------------------------------
  838. When Used:
  839.     
  840. ******************************************************************************
  841. */
  842. static void p2wi_GetTERect(const p2w_WindowPtr thep2wWindow, Rect *teRect)
  843. {
  844.     *teRect = ((WindowPtr)thep2wWindow)->portRect;
  845.     InsetRect(teRect, kTextMargin, kTextMargin);    /* adjust for margin */
  846.     teRect->bottom = teRect->bottom - 15;        /* and for the scrollbars */
  847.     teRect->right = teRect->right - 15;
  848. } // p2wi_GetTERect
  849.  
  850.  
  851. /*
  852. ******************************************************************************
  853. Name:
  854.     p2wi_AdjustTE
  855. ------------------------------------------------------------------------------
  856. Purpose:
  857.     Scroll the TERec around to match up to the potentially updated scrollbar
  858.     values. This is really useful when the window has been resized such that
  859.     the scrollbars became inactive but the TERec was already scrolled.
  860. ------------------------------------------------------------------------------
  861. Description:
  862.     
  863. ------------------------------------------------------------------------------
  864. Parameters:
  865.     
  866. ------------------------------------------------------------------------------
  867. When Used:
  868.     
  869. ******************************************************************************
  870. */
  871. static void p2wi_AdjustTE(const p2w_WindowPtr thep2wWindow)
  872. {
  873.     short        hVal,vVal;
  874.     TEPtr        te;
  875.     
  876.     vVal = GetCtlValue(thep2wWindow->p2wVScroller);
  877.     hVal = GetCtlValue(thep2wWindow->p2wHScroller);
  878.     te = *thep2wWindow->p2wTEHandle;
  879.     TEScroll((te->viewRect.left - te->destRect.left) - hVal,
  880.             (te->viewRect.top - te->destRect.top) - (vVal * te->lineHeight),
  881.             thep2wWindow->p2wTEHandle);
  882. } // p2wi_AdjustTE
  883.  
  884.  
  885. /*
  886. ******************************************************************************
  887. Name:
  888.     p2wi_AdjustViewRect
  889. ------------------------------------------------------------------------------
  890. Purpose:
  891.     Update our TE view rect so it's the greatest multiple of
  892.     the lineHeight that still fits in the old viewRect.
  893. ------------------------------------------------------------------------------
  894. Description:
  895.     
  896. ------------------------------------------------------------------------------
  897. Parameters:
  898.     
  899. ------------------------------------------------------------------------------
  900. When Used:
  901.     
  902. ******************************************************************************
  903. */
  904. static void p2wi_AdjustViewRect(TEHandle p2wTE)
  905. {
  906.     TEPtr        te;
  907.     
  908.     te = *p2wTE;
  909.     te->viewRect.bottom = (((te->viewRect.bottom - te->viewRect.top) / te->lineHeight)
  910.                             * te->lineHeight) + te->viewRect.top;
  911. } // p2wi_AdjustViewRect
  912.  
  913.  
  914. /*
  915. ******************************************************************************
  916. Name:
  917.     p2wi_CommonAdjustScroller
  918. ------------------------------------------------------------------------------
  919. Purpose:
  920.     Calculate the new control maximum value and current value,
  921.     for the horizontal or vertical scrollbar. The vertical max
  922.     is calculated by comparing the number of lines to the
  923.     vertical size of the viewRect. The horizontal max is
  924.     calculated by comparing the maximum document width to the
  925.     width of the viewRect. The current values are set by
  926.     comparing the offset between the view and destination
  927.     rects. If necessary and we canRedraw, have the control be
  928.     re-drawn by calling ShowControl. 
  929. ------------------------------------------------------------------------------
  930. Description:
  931.     
  932. ------------------------------------------------------------------------------
  933. Parameters:
  934.     
  935. ------------------------------------------------------------------------------
  936. When Used:
  937.     Called by p2wi_AdjustScrollValues, twice.
  938. ******************************************************************************
  939. */
  940. static void p2wi_CommonAdjustScroller(const Boolean isVert, const p2w_WindowPtr thep2wWindow, ControlHandle control, TEHandle theTEHandle, const Boolean canRedraw)
  941. {
  942.     short        value, lines, max;
  943.     short        oldValue, oldMax;
  944.     
  945.     oldValue = GetCtlValue(control);
  946.     oldMax = GetCtlMax(control);
  947.     if (isVert)
  948.     {
  949.         lines = (**theTEHandle).nLines;
  950.         /* since nLines isn╒t right if the last character is a return, check for that case */
  951.         if ( *(*(**theTEHandle).hText + (**theTEHandle).teLength - 1) == '\r')
  952.             lines += 1;
  953.         max = lines - (((**theTEHandle).viewRect.bottom - (**theTEHandle).viewRect.top) / (**theTEHandle).lineHeight);
  954.     }
  955.     else
  956.         max = thep2wWindow->p2wMaxDocWidth - ((**theTEHandle).viewRect.right - (**theTEHandle).viewRect.left);
  957.     
  958.     if (max < 0)
  959.         max = 0;
  960.     SetCtlMax(control, max);
  961.     
  962.     if (isVert)
  963.     {
  964.         // always scroll to end?
  965.         if (thep2wWindow->p2wAlwaysScrollToBottom)
  966.             value = max;
  967.         else
  968.             value = ((**theTEHandle).viewRect.top - (**theTEHandle).destRect.top) / (**theTEHandle).lineHeight;
  969.     }
  970.     else
  971.         value = (**theTEHandle).viewRect.left - (**theTEHandle).destRect.left;
  972.     
  973.     if ( value < 0 )
  974.         value = 0;
  975.     else
  976.         if (value >  max)
  977.             value = max;
  978.     
  979.     SetCtlValue(control, value);
  980.  
  981.     /* now redraw the control if it needs to be and can be */
  982.     if (canRedraw || (max != oldMax) || (value != oldValue))
  983.     {
  984. //        InvalRect(&(**control).contrlRect);
  985.         Draw1Control(control);
  986.     }
  987. } // p2wi_CommonAdjustScroller
  988.  
  989.  
  990. /*
  991. ******************************************************************************
  992. Name:
  993.     p2wi_AdjustScrollValues
  994. ------------------------------------------------------------------------------
  995. Purpose:
  996.     Simply call the common adjust routine for both the vertical
  997.     and horizontal scrollbars.
  998. ------------------------------------------------------------------------------
  999. Description:
  1000.     
  1001. ------------------------------------------------------------------------------
  1002. Parameters:
  1003.     
  1004. ------------------------------------------------------------------------------
  1005. When Used:
  1006.     
  1007. ******************************************************************************
  1008. */
  1009. static void p2wi_AdjustScrollValues(const p2w_WindowPtr thep2wWindow, const Boolean doRedraw)
  1010. {
  1011.     p2wi_CommonAdjustScroller(true, thep2wWindow, thep2wWindow->p2wVScroller, thep2wWindow->p2wTEHandle, doRedraw);
  1012.     p2wi_CommonAdjustScroller(false, thep2wWindow, thep2wWindow->p2wHScroller, thep2wWindow->p2wTEHandle, doRedraw);
  1013. } // p2wi_AdjustScrollValues
  1014.  
  1015.  
  1016.  
  1017. /*
  1018. ******************************************************************************
  1019. Name:
  1020.     p2wi_AdjustScrollSizes
  1021. ------------------------------------------------------------------------------
  1022. Purpose:
  1023.     Re-calculate the position and size of the viewRect and the
  1024.     scrollbars. The constant kScrollTweek compensates for the
  1025.     "off-by-one" requirements of the scrollbars that need their
  1026.     borders coinciding with the growbox. 
  1027. ------------------------------------------------------------------------------
  1028. Description:
  1029.     
  1030. ------------------------------------------------------------------------------
  1031. Parameters:
  1032.     
  1033. ------------------------------------------------------------------------------
  1034. When Used:
  1035.     
  1036. ******************************************************************************
  1037. */
  1038. static void p2wi_AdjustScrollSizes(const p2w_WindowPtr thep2wWindow)
  1039. {
  1040.     Rect        teRect;
  1041.     p2wi_GetTERect(thep2wWindow, &teRect);    // start with TERect..
  1042.     (*thep2wWindow->p2wTEHandle)->viewRect = teRect;
  1043.     p2wi_AdjustViewRect(thep2wWindow->p2wTEHandle);    /* snap to nearest line */
  1044.  
  1045.     /* Vertical */
  1046.     MoveControl(thep2wWindow->p2wVScroller,
  1047.                 ((WindowPtr)thep2wWindow)->portRect.right - kScrollbarAdjust,
  1048.                 -1);
  1049.     SizeControl(thep2wWindow->p2wVScroller,
  1050.                 kScrollbarWidth,
  1051.                 (((WindowPtr)thep2wWindow)->portRect.bottom
  1052.                     - ((WindowPtr)thep2wWindow)->portRect.top)
  1053.                     - (kScrollbarAdjust - kScrollTweek));
  1054.  
  1055.     /* Horizontal */
  1056.     MoveControl(thep2wWindow->p2wHScroller,
  1057.                 -1,
  1058.                 ((WindowPtr)thep2wWindow)->portRect.bottom - kScrollbarAdjust);
  1059.     SizeControl(thep2wWindow->p2wHScroller,
  1060.                 (((WindowPtr)thep2wWindow)->portRect.right
  1061.                     - ((WindowPtr)thep2wWindow)->portRect.left)
  1062.                     - (kScrollbarAdjust - kScrollTweek),
  1063.                 kScrollbarWidth);
  1064. } // p2wi_AdjustScrollSizes
  1065.  
  1066.  
  1067. /*
  1068. ******************************************************************************
  1069. Name:
  1070.     p2wi_AdjustScrollbars
  1071. ------------------------------------------------------------------------------
  1072. Purpose:
  1073.     Recalculate the scrollbar pos/values, and redraw if need be.
  1074. ------------------------------------------------------------------------------
  1075. Description:
  1076.     Turn off the controls by jamming a zero into their contrlVis fields
  1077.     (HideControl erases them and we don't want that). If the controls
  1078.     are to be resized as well, call the procedure to do that, then call
  1079.     the procedure to adjust the maximum and current values. Finally,
  1080.     re-enable the controls by jamming a $FF in their contrlVis fields.  
  1081. ------------------------------------------------------------------------------
  1082. Parameters:
  1083.     
  1084. ------------------------------------------------------------------------------
  1085. When Used:
  1086.     
  1087. ******************************************************************************
  1088. */
  1089. static void p2wi_AdjustScrollbars(const p2w_WindowPtr thep2wWindow, const Boolean doResize)
  1090. {
  1091.     short    oldHvis, oldVvis;
  1092.  
  1093.     oldVvis = (**thep2wWindow->p2wVScroller).contrlVis;
  1094.     oldHvis = (**thep2wWindow->p2wHScroller).contrlVis;
  1095.  
  1096.     /* First, turn visibility of scrollbars off to eliminate unwanted redrawing */
  1097.     (*thep2wWindow->p2wVScroller)->contrlVis = kControlInvisible;    /* turn them off */
  1098.     (*thep2wWindow->p2wHScroller)->contrlVis = kControlInvisible;
  1099.  
  1100.     /* move & size as needed */
  1101.     if (doResize)
  1102.         p2wi_AdjustScrollSizes(thep2wWindow);
  1103.  
  1104.     /* adjust constrols' max and current values */
  1105.     p2wi_AdjustScrollValues(thep2wWindow, doResize);
  1106.  
  1107.     /* now scroll the TE record to match the scrollbars */
  1108.     p2wi_AdjustTE(thep2wWindow);
  1109.  
  1110.     /* Now, restore visibility in case we never had to ShowControl during adjustment */
  1111.     (*thep2wWindow->p2wVScroller)->contrlVis = oldVvis;    /* restore them */
  1112.     (*thep2wWindow->p2wHScroller)->contrlVis = oldHvis;
  1113. } // p2wi_AdjustScrollbars
  1114.  
  1115.  
  1116. /*
  1117. ******************************************************************************
  1118. Name:
  1119.     p2wi_ResizeWindow
  1120. ------------------------------------------------------------------------------
  1121. Purpose:
  1122.     Called when the window has been resized to fix up the controls and content.
  1123. ------------------------------------------------------------------------------
  1124. Description:
  1125.     
  1126. ------------------------------------------------------------------------------
  1127. Parameters:
  1128.     
  1129. ------------------------------------------------------------------------------
  1130. When Used:
  1131.     
  1132. ******************************************************************************
  1133. */
  1134. static void p2wi_ResizeWindow(const p2w_WindowPtr thep2wWindow)
  1135. {
  1136.     p2wi_AdjustScrollbars(thep2wWindow, true);
  1137.     InvalRect(&((WindowPtr)thep2wWindow)->portRect);
  1138. } // p2wi_ResizeWindow
  1139.  
  1140.  
  1141.  
  1142. /*
  1143. ******************************************************************************
  1144. Name:
  1145.     p2wi_GetLocalUpdateRegion
  1146. ------------------------------------------------------------------------------
  1147. Purpose:
  1148.     Returns the update region in local coordinates
  1149. ------------------------------------------------------------------------------
  1150. Description:
  1151.     
  1152. ------------------------------------------------------------------------------
  1153. Parameters:
  1154.     
  1155. ------------------------------------------------------------------------------
  1156. When Used:
  1157.     
  1158. ******************************************************************************
  1159. */
  1160. static void p2wi_GetLocalUpdateRegion(const p2w_WindowPtr thep2wWindow, RgnHandle localRgn)
  1161. {
  1162.     CopyRgn(((WindowPeek)thep2wWindow)->updateRgn, localRgn);    /* save old update region */
  1163.     OffsetRgn(localRgn, ((WindowPtr)thep2wWindow)->portBits.bounds.left,
  1164.                         ((WindowPtr)thep2wWindow)->portBits.bounds.top);
  1165. } // p2wi_GetLocalUpdateRegion
  1166.  
  1167.  
  1168.  
  1169. /*
  1170. ******************************************************************************
  1171. Name:
  1172.     p2wi_CommonScrollAction
  1173. ------------------------------------------------------------------------------
  1174. Purpose:
  1175.     Common algorithm for pinning the value of a control. It
  1176.     returns the actual amount the value of the control changed.
  1177.     Note the pinning is done for the sake of returning the
  1178.     amount the control value changed.
  1179. ------------------------------------------------------------------------------
  1180. Description:
  1181.     
  1182. ------------------------------------------------------------------------------
  1183. Parameters:
  1184.     
  1185. ------------------------------------------------------------------------------
  1186. When Used:
  1187.     Called by p2wi_HScrollActionProc, p2wi_VScrollActionProc
  1188. ******************************************************************************
  1189. */
  1190. static void p2wi_CommonScrollAction(ControlHandle control, short *amount)
  1191. {
  1192.     short        value, max;
  1193.     
  1194.     /* get the current value.. */
  1195.     value = GetCtlValue(control);
  1196.  
  1197.     /* and the biggest value */
  1198.     max = GetCtlMax(control);
  1199.  
  1200.     *amount = value - *amount;
  1201.     if ( *amount < 0 )
  1202.         *amount = 0;
  1203.     else if ( *amount > max )
  1204.         *amount = max;
  1205.     SetCtlValue(control, *amount);
  1206.  
  1207.     /* figure out the delta change */
  1208.     *amount = value - *amount;
  1209. } // p2wi_CommonScrollAction
  1210.  
  1211.  
  1212. /*
  1213. ******************************************************************************
  1214. Name:
  1215.     p2wi_VScrollActionProc
  1216. ------------------------------------------------------------------------------
  1217. Purpose:
  1218.     Determines how much to change the value of the vertical scrollbar by,
  1219.     and how much to scroll the TE record.
  1220. ------------------------------------------------------------------------------
  1221. Description:
  1222.     
  1223. ------------------------------------------------------------------------------
  1224. Parameters:
  1225.     
  1226. ------------------------------------------------------------------------------
  1227. When Used:
  1228.     Callback routine, called by toolbox
  1229. ******************************************************************************
  1230. */
  1231. pascal void p2wi_VScrollActionProc(ControlHandle control, short part)
  1232. {
  1233.     short            amount;
  1234.     p2w_WindowPtr    p2w_Window;
  1235.     TEPtr            te;
  1236.     
  1237.     if (part != 0)
  1238.     {    /* if it was actually in the control */
  1239.         p2w_Window = (p2w_WindowPtr)(*control)->contrlOwner;
  1240.         te = *p2w_Window->p2wTEHandle;
  1241.         switch (part)
  1242.         {
  1243.             case inUpButton:
  1244.             case inDownButton:        /* one line */
  1245.                 amount = 1;
  1246.                 break;
  1247.             case inPageUp:            /* one page */
  1248.             case inPageDown:
  1249.                 amount = (te->viewRect.bottom - te->viewRect.top) / te->lineHeight;
  1250.                 break;
  1251.         }
  1252.         if ((part == inDownButton) || (part == inPageDown))
  1253.             amount = -amount;        /* reverse direction if going down */
  1254.         p2wi_CommonScrollAction(control, &amount);
  1255.         if (amount != 0)
  1256.             TEScroll(0, amount * te->lineHeight, p2w_Window->p2wTEHandle);
  1257.     }
  1258. } // p2wi_VScrollActionProc
  1259.  
  1260.  
  1261. /*
  1262. ******************************************************************************
  1263. Name:
  1264.     p2wi_HScrollActionProc
  1265. ------------------------------------------------------------------------------
  1266. Purpose:
  1267.     Determines how much to change the value of the horizontal scrollbar by,
  1268.     and how much to scroll the TE record.
  1269. ------------------------------------------------------------------------------
  1270. Description:
  1271.     
  1272. ------------------------------------------------------------------------------
  1273. Parameters:
  1274.     
  1275. ------------------------------------------------------------------------------
  1276. When Used:
  1277.     Callback routine, called by toolbox
  1278. ******************************************************************************
  1279. */
  1280. pascal void p2wi_HScrollActionProc(ControlHandle control, short part)
  1281. {
  1282.     short        amount;
  1283.     p2w_WindowPtr    p2w_Window;
  1284.     TEPtr        te;
  1285.     
  1286.     if (part != 0)
  1287.     {    /* if it was actually in the control */
  1288.         p2w_Window = (p2w_WindowPtr)(*control)->contrlOwner;
  1289.         te = *p2w_Window->p2wTEHandle;
  1290.         switch (part)
  1291.         {
  1292.             case inUpButton:
  1293.             case inDownButton:        /* some pixels */
  1294.                 amount = kButtonScroll;
  1295.                 break;
  1296.             case inPageUp:            /* a whole page */
  1297.             case inPageDown:
  1298.                 amount = te->viewRect.right - te->viewRect.left;
  1299.                 break;
  1300.         }
  1301.         if ( (part == inDownButton) || (part == inPageDown) )
  1302.             amount = -amount;        /* reverse direction.. */
  1303.         p2wi_CommonScrollAction(control, &amount);
  1304.         if ( amount != 0 )
  1305.             TEScroll(amount, 0, p2w_Window->p2wTEHandle);
  1306.     }
  1307. } // p2wi_HScrollActionProc
  1308.  
  1309.  
  1310. /*---------------------------------------------------------------------*/
  1311. /*==== Standard C library fns ====*/
  1312.  
  1313. /*
  1314. ******************************************************************************
  1315. Name:
  1316.     p2w_StdCOut_BottleNeck
  1317. ------------------------------------------------------------------------------
  1318. Purpose:
  1319.     Internal Standard C output replacement common bottleneck routine..
  1320.     This is what they all call to actually display the string/character.
  1321. ------------------------------------------------------------------------------
  1322. Description:
  1323.     
  1324. ------------------------------------------------------------------------------
  1325. Parameters:
  1326.     
  1327. ------------------------------------------------------------------------------
  1328. When Used:
  1329.     
  1330. ******************************************************************************
  1331. */
  1332. static int p2w_StdCOut_BottleNeck(const FILE *stream)
  1333. {
  1334.     int        x;
  1335.     char    *OutBuf, *outp;
  1336.  
  1337.     // If the output is for standard output (stderr/stdout) then capture it into our window,
  1338.     // else send it on to the standard C file output library routine.
  1339.     if ((stream == stderr) || (stream == stdout))
  1340.     {
  1341.         // get ahold of output buffer
  1342.         OutBuf = *p2w_Stdio_OutBuf_Hdl;
  1343.         // make sure the string at least stops here! (maybe check strlen first for overflow errors?)
  1344.         *(OutBuf+kMaxStdIOBuffSize-1) = '\0';
  1345.     
  1346.         // Replace any line feeds (0x0a) with Macintosh carriage returns (0x0d)
  1347.         // This is mainly for Think C compatibility, since Think faithfully
  1348.         // literally adopted the K&R C idea (from Unix) that '\n' is really 0x0a,
  1349.         // and Apple's MPW C bends '\n' to 0x0d for better file compatibility.
  1350.  
  1351. /* Note: For now, do this in both MPW and Think C.  This will FORCE the mapping
  1352. of any LFs to CRs.  The main reason for doing this is to catch the odd times
  1353. that the source code uses either '\r', or worse, '\0x0a' to emebed returns! */
  1354. /*        if ('\n' != 0x0d) -- commented out to force issue, per above comment */
  1355.         {
  1356.             outp = OutBuf;
  1357.             while (*outp)
  1358.             {
  1359.                 if (*outp == 0x0a)
  1360.                   *outp = 0x0d;
  1361.                 outp++;
  1362.             }
  1363.         }
  1364.     
  1365.         x = p2w_AddCString(local_p2wWindow, OutBuf);    // add it into window
  1366.     }
  1367.     else
  1368.     {
  1369.         // call a real std. C library routine.  This allows output to real
  1370.         // stdio C files to pass through unmolested.
  1371. /*        x = fputs(OutBuf, stream); -- not quite the way to do it.. */
  1372.     }
  1373.  
  1374.     return x;
  1375.  
  1376. } // p2w_StdCOut_BottleNeck
  1377.  
  1378.  
  1379. /*
  1380. ******************************************************************************
  1381. Name:
  1382.     p2w_vfprintf
  1383. ------------------------------------------------------------------------------
  1384. Purpose:
  1385.     Internal common formatting handler for fprintf/printf
  1386. ------------------------------------------------------------------------------
  1387. Description:
  1388.     
  1389. ------------------------------------------------------------------------------
  1390. Parameters:
  1391.     
  1392. ------------------------------------------------------------------------------
  1393. When Used:
  1394.     
  1395. ******************************************************************************
  1396. */
  1397. static int p2w_vfprintf(FILE *stream, const char *format, va_list va_args)
  1398. {
  1399.     int        x;
  1400.     char    *outBuf;
  1401.  
  1402.     // get ahold of output buffer
  1403.     HLock(p2w_Stdio_OutBuf_Hdl);
  1404.     outBuf = *p2w_Stdio_OutBuf_Hdl;
  1405.  
  1406. #ifdef NEEDS_DEBUG
  1407. {
  1408.     // stick in a TE-length value debug into the TE record
  1409.     int daLen = (**(local_p2wWindow->p2wTEHandle)).teLength;
  1410.     sprintf(outBuf, "[%5d] ",daLen);
  1411.     x = p2w_StdCOut_BottleNeck(stream);
  1412. }
  1413. #endif NEEDS_DEBUG
  1414.  
  1415.     // use C library routine to do printf formatting of the string into buffer
  1416.     x = vsprintf(outBuf, format, va_args); // format it into a string
  1417.  
  1418.     // do the window output
  1419.     x = p2w_StdCOut_BottleNeck(stream);
  1420.  
  1421.     // cut buffer adrift again..
  1422.     HUnlock(p2w_Stdio_OutBuf_Hdl);
  1423.  
  1424.     return x;
  1425. } // p2w_vfprintf
  1426.  
  1427.  
  1428.  
  1429. int p2w_fflush(FILE *stream)
  1430. {
  1431. #pragma unused (stream)
  1432.     int        x;
  1433.  
  1434.     /* major no-op, dude */
  1435.     x = 0;
  1436.     return x;
  1437. } // p2w_fflush
  1438.  
  1439.  
  1440.  
  1441.  
  1442. int p2w_fprintf(FILE *stream, const char *format, ...)
  1443. {
  1444.     va_list    va_args;
  1445.     int        x;
  1446.  
  1447.     // use our bottleneck routine to do printf formatting
  1448.     va_start(va_args, format);
  1449.     x = p2w_vfprintf(stream, format, va_args); // format it into a string
  1450.     va_end(va_args);
  1451.  
  1452.     return x;
  1453. } // p2w_fprintf
  1454.  
  1455.  
  1456. int p2w_fputc(int theChar, FILE *stream)
  1457. {
  1458.     int        x;
  1459.     char    *outBuf;
  1460.  
  1461.     // get ahold of output buffer & make char into string
  1462.     HLock(p2w_Stdio_OutBuf_Hdl);
  1463.     outBuf = *p2w_Stdio_OutBuf_Hdl;
  1464.  
  1465.     outBuf[0] = theChar;
  1466.     outBuf[1] = '\0';
  1467.  
  1468.     x = p2w_StdCOut_BottleNeck(stream);
  1469.  
  1470.     HUnlock(p2w_Stdio_OutBuf_Hdl);
  1471.  
  1472.     return x;
  1473.  
  1474. } // p2w_fputc
  1475.  
  1476.  
  1477. int p2w_fputs(const char *theString, FILE *stream)
  1478. {
  1479.     int        x;
  1480.     char    *outBuf;
  1481.  
  1482.     // get ahold of output buffer
  1483.     HLock(p2w_Stdio_OutBuf_Hdl);
  1484.     outBuf = *p2w_Stdio_OutBuf_Hdl;
  1485.  
  1486.     // Copy string into buffer & write it
  1487.     BlockMove(theString, outBuf, kMaxStdIOBuffSize);
  1488.     x = p2w_StdCOut_BottleNeck(stream);
  1489.  
  1490.     // cut buffer adrift again..
  1491.     HUnlock(p2w_Stdio_OutBuf_Hdl);
  1492.  
  1493.     return x;
  1494. } // p2w_fputs
  1495.  
  1496.  
  1497. int p2w_printf(const char * format, ...)
  1498. {
  1499.     va_list    va_args;
  1500.     int        x;
  1501.  
  1502.     // use our bottleneck routine to do printf formatting
  1503.     va_start(va_args, format);
  1504.     x = p2w_vfprintf(stdout, format, va_args); // format it into a string
  1505.     va_end(va_args);
  1506.  
  1507.     return x;
  1508. } // p2w_printf
  1509.  
  1510.  
  1511. int p2w_putc(int theChar, FILE *stream)
  1512. {
  1513.     return p2w_fputc(theChar, stream);
  1514. } // p2w_putc
  1515.  
  1516.  
  1517. int p2w_putchar(const char theChar)
  1518. {
  1519.     return p2w_fputc(theChar, stdout);
  1520. } // p2w_putchar
  1521.  
  1522.  
  1523. int p2w_puts(const char *theString)
  1524. {
  1525.     return p2w_fputs(theString, stdout);
  1526. } // p2w_puts
  1527.